﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Windows.Threading;
using System.Collections;
using TcpIpServerTest.Network;

namespace TcpIpServerTest
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        TcpService serviceTCP = new TcpService();

        char startChar = (char)0x0b;
        char endChar = (char)0x1c;
        char newLineChar = (char)0x0d;

        const int myPort = 2100;
        int counterConnection = 0;
        Thread threadListener = null;
        TcpListener listener;

        public Window1()
        {
            InitializeComponent();
            initializeUI();
            
            IPEndPoint endP= new IPEndPoint(IPAddress.Any, 2100);
            serviceTCP.TcpConnectionAccepted = ConnectionAccepted;
            serviceTCP.Start(endP);
                        
            /*listener = new TcpListener(IPAddress.Any, myPort);
            listener.Start();

            threadListener = new Thread(new ThreadStart(ListenerService));
            threadListener.IsBackground = true;
            threadListener.Start();*/
        }
        


        private void ConnectionAccepted(TcpConnection tcpConnection)
        {
            byte[] data = tcpConnection.Receive();
            while (data != null) {

                String m = extractHL7Message(Utils.byteArrayToCharArray(data));               
                renderHL7Message(m, tcpConnection.connectionNumber);                
                byte[] temp = Utils.stringToByteArray(getACKMessage());
                tcpConnection.Send(temp);
                data = tcpConnection.Receive();
            }
                      
        }

        private void initializeUI()
        {
            label4.Content = "Listening port " + myPort + "     IP : " + Utils.getMyIp();
        }

        public void ListenerService()
        {
            try
            {
                while (true)
                {
                    Socket soc = listener.AcceptSocket();

                    Thread thTemp = new Thread(delegate()
                    {
                        HL7ConnectionServiceForSocket(soc);
                    });
                    thTemp.IsBackground = true;
                    thTemp.Start();
                }
            }
            // Thrown when the thread is interupted by
            // the main thread - exiting the loop
            catch (ThreadInterruptedException)
            {
                // Simply exit....
            }
            catch (Exception) { }
            addItemToList("Thread Exited");
        }

        private void renderHL7Message(String message, int connectionNumber)
        {

            if (!(message == "" || message == null))
            {
                addItemToList(message + "I'm from connection : " + connectionNumber);
                try
                {
                    if (!message.Equals(""))
                    {
                        String temp = HL7Samples.parseMessageXML(message);
                    }
                }
                catch { }
            }
        }

        private String getACKMessage()
        {

            String mm = @"MSH|^~\&|HIS|System|Hosp|HL7 Genie|20071016055244||ACK^A01|A234242|P|2.3.1|" +
                            newLineChar + @"MSA|AA|234242|Message Received Successfully|";
            mm = startChar + mm + newLineChar + endChar + newLineChar;
            return mm;
        }

        public void HL7ConnectionServiceForSocket(Socket soc)
        {
            counterConnection++;
            int myConnectionNumber = counterConnection;
            addItemToList("Connection established with client : " + myConnectionNumber);
            Stream s = null;
            try
            {
                
                s = new NetworkStream(soc);
                
                StreamReader sr = new StreamReader(s);
                StreamWriter sw = new StreamWriter(s);
                sw.AutoFlush = true; //enable automatic flushing
                
                while (true)  // FIX ME
                {
                    bool isHL7 = false;
                    Thread.Sleep(10);  // FIX ME
                    string message = "";                               
                    String lineMessage = "";
                    int chInt;

                    chInt = sr.Read();
                    if (chInt == (int)startChar)
                    {
                        isHL7 = true;
                    }
                    else {
                        lineMessage += (char)chInt;
                    }
                    while ((chInt = sr.Read()) != -1)
                    {                        
                        char ch = (char)chInt;
                        if (isHL7)
                        {
                            if (ch == newLineChar) //   \r
                            {
                                message += (char)ch;
                                lineMessage += (char)ch;
                                lineMessage = "";
                            }
                            else if (ch == startChar)//  \v start message
                            {
                                lineMessage = "";
                            }
                            else if (ch == endChar)//  end transmission = (int)28
                            {
                                lineMessage = "";
                                renderHL7Message(message, myConnectionNumber);
                                sw.Write(getACKMessage());
                                break;
                            }
                            else
                            {
                                message += (char)ch;                                
                            }
                        }
                        else {
                            lineMessage += (char)ch;
                            if (ch == newLineChar) {

                                addItemToList(lineMessage);
                                lineMessage = "";
                            }                                
                        }
                    }             
                }                
            }
            catch (Exception) { }
            finally {             
                if (s != null) s.Close(); 
            }            
            //soc.Disconnect(true);
            soc.Close();
            
            addItemToList("Connection Lost : " + myConnectionNumber);           
        }

        ArrayList charList = new ArrayList();
        private String extractHL7Message(char[] message)
        {
            for (int i = 0; i < message.Length; i++)
            {

                char ch = message[i];
                if (ch == startChar)
                {
                    charList.Clear();
                }
                else if (ch == newLineChar)
                {
                    charList.Add(ch);
                }
                else if (ch == endChar)
                {
                    String completeHL7message = "";
                    foreach (char c in charList)
                    {
                        completeHL7message += c;
                    }
                    charList.Clear();
                    return completeHL7message;
                }
                else
                {
                    charList.Add(ch);
                }
            }
            return "";
        }

        private void addItemToList(String temp)
        {
            processDelegateBeginInvoke(new Action(delegate()
            {
                listBox1.Items.Add(temp);
                int index = listBox1.Items.Count - 1;
                Object item = listBox1.Items.GetItemAt(index);
                listBox1.SelectedIndex = index;
                //listBox1.ScrollIntoView(item);
            }));
        }

        private void processDelegateBeginInvoke(Action act)
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, act);
        }

        private void processDelegateInvoke(Action act)
        {
            this.Dispatcher.Invoke(DispatcherPriority.DataBind, act);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            StopThreads();
        }

        // Stop the background threads
        private void StopThreads()
        {
            if (threadListener != null)
            {
                threadListener.Interrupt();
            }
        }
    }
}
